using System;
using System.Drawing;
using System.Collections;
using System.ComponentModel;
using System.Windows.Forms;
using System.Data;
using System.IO;

namespace SQScriptRunner
{
	/// <summary>
	/// Summary description for Form1.
	/// </summary>
	public class frmMain : System.Windows.Forms.Form
	{
		private System.Windows.Forms.Panel panel1;
		private System.Windows.Forms.Button btnGo;
		private System.Windows.Forms.GroupBox gbDatabaseParameters;
		private System.Windows.Forms.TextBox txtPassword;
		private System.Windows.Forms.Label label4;
		private System.Windows.Forms.TextBox txtUserAccount;
		private System.Windows.Forms.Label label3;
		private System.Windows.Forms.TextBox txtDatabaseName;
		private System.Windows.Forms.Label label1;
		internal System.Windows.Forms.Button btnBrowse;
		internal System.Windows.Forms.TextBox txtFilePath;
		internal System.Windows.Forms.OpenFileDialog OpenFileDialog1;
		private System.Windows.Forms.GroupBox groupBox1;
		private System.Windows.Forms.TextBox txtServer;
		private System.Windows.Forms.Label label2;
		private System.Windows.Forms.GroupBox gbScripts;
		internal System.Windows.Forms.Button btnBrowseForServersFile;
		internal System.Windows.Forms.TextBox txtServersFile;
		private System.Windows.Forms.CheckedListBox lbScripts;
		private System.Windows.Forms.Label label5;
		private System.Windows.Forms.Button btnAddToList;
		private System.Windows.Forms.RadioButton radMultipleServers;
		private System.Windows.Forms.RadioButton radSingleServer;
		private System.Windows.Forms.Timer timer1;
		private System.ComponentModel.IContainer components;
		private System.Windows.Forms.TextBox tbStatus;

		private Queue mServerQueue = new Queue();

		public frmMain()
		{
			//
			// Required for Windows Form Designer support
			//
			InitializeComponent();

			//
			// TODO: Add any constructor code after InitializeComponent call
			//
		}

		/// <summary>
		/// Clean up any resources being used.
		/// </summary>
		protected override void Dispose( bool disposing )
		{
			if( disposing )
			{
				if (components != null) 
				{
					components.Dispose();
				}
			}
			base.Dispose( disposing );
		}

		#region Windows Form Designer generated code
		/// <summary>
		/// Required method for Designer support - do not modify
		/// the contents of this method with the code editor.
		/// </summary>
		private void InitializeComponent()
		{
			this.components = new System.ComponentModel.Container();
			this.panel1 = new System.Windows.Forms.Panel();
			this.groupBox1 = new System.Windows.Forms.GroupBox();
			this.btnBrowseForServersFile = new System.Windows.Forms.Button();
			this.txtServersFile = new System.Windows.Forms.TextBox();
			this.txtServer = new System.Windows.Forms.TextBox();
			this.label2 = new System.Windows.Forms.Label();
			this.radMultipleServers = new System.Windows.Forms.RadioButton();
			this.radSingleServer = new System.Windows.Forms.RadioButton();
			this.gbScripts = new System.Windows.Forms.GroupBox();
			this.btnAddToList = new System.Windows.Forms.Button();
			this.label5 = new System.Windows.Forms.Label();
			this.lbScripts = new System.Windows.Forms.CheckedListBox();
			this.btnBrowse = new System.Windows.Forms.Button();
			this.txtFilePath = new System.Windows.Forms.TextBox();
			this.gbDatabaseParameters = new System.Windows.Forms.GroupBox();
			this.txtPassword = new System.Windows.Forms.TextBox();
			this.label4 = new System.Windows.Forms.Label();
			this.txtUserAccount = new System.Windows.Forms.TextBox();
			this.label3 = new System.Windows.Forms.Label();
			this.txtDatabaseName = new System.Windows.Forms.TextBox();
			this.label1 = new System.Windows.Forms.Label();
			this.btnGo = new System.Windows.Forms.Button();
			this.OpenFileDialog1 = new System.Windows.Forms.OpenFileDialog();
			this.timer1 = new System.Windows.Forms.Timer(this.components);
			this.tbStatus = new System.Windows.Forms.TextBox();
			this.panel1.SuspendLayout();
			this.groupBox1.SuspendLayout();
			this.gbScripts.SuspendLayout();
			this.gbDatabaseParameters.SuspendLayout();
			this.SuspendLayout();
			// 
			// panel1
			// 
			this.panel1.Controls.Add(this.groupBox1);
			this.panel1.Controls.Add(this.gbScripts);
			this.panel1.Controls.Add(this.gbDatabaseParameters);
			this.panel1.Controls.Add(this.btnGo);
			this.panel1.Dock = System.Windows.Forms.DockStyle.Top;
			this.panel1.Location = new System.Drawing.Point(0, 0);
			this.panel1.Name = "panel1";
			this.panel1.Size = new System.Drawing.Size(736, 400);
			this.panel1.TabIndex = 0;
			// 
			// groupBox1
			// 
			this.groupBox1.Controls.Add(this.btnBrowseForServersFile);
			this.groupBox1.Controls.Add(this.txtServersFile);
			this.groupBox1.Controls.Add(this.txtServer);
			this.groupBox1.Controls.Add(this.label2);
			this.groupBox1.Controls.Add(this.radMultipleServers);
			this.groupBox1.Controls.Add(this.radSingleServer);
			this.groupBox1.Location = new System.Drawing.Point(8, 8);
			this.groupBox1.Name = "groupBox1";
			this.groupBox1.Size = new System.Drawing.Size(712, 88);
			this.groupBox1.TabIndex = 17;
			this.groupBox1.TabStop = false;
			this.groupBox1.Text = "Target(s)";
			// 
			// btnBrowseForServersFile
			// 
			this.btnBrowseForServersFile.Location = new System.Drawing.Point(672, 48);
			this.btnBrowseForServersFile.Name = "btnBrowseForServersFile";
			this.btnBrowseForServersFile.Size = new System.Drawing.Size(24, 24);
			this.btnBrowseForServersFile.TabIndex = 15;
			this.btnBrowseForServersFile.Text = "...";
			this.btnBrowseForServersFile.Click += new System.EventHandler(this.btnBrowseForServersFile_Click);
			// 
			// txtServersFile
			// 
			this.txtServersFile.Location = new System.Drawing.Point(328, 48);
			this.txtServersFile.Name = "txtServersFile";
			this.txtServersFile.Size = new System.Drawing.Size(336, 20);
			this.txtServersFile.TabIndex = 14;
			this.txtServersFile.Text = "";
			// 
			// txtServer
			// 
			this.txtServer.Location = new System.Drawing.Point(96, 40);
			this.txtServer.Name = "txtServer";
			this.txtServer.TabIndex = 13;
			this.txtServer.Text = "";
			// 
			// label2
			// 
			this.label2.Location = new System.Drawing.Point(8, 40);
			this.label2.Name = "label2";
			this.label2.Size = new System.Drawing.Size(88, 16);
			this.label2.TabIndex = 12;
			this.label2.Text = "Server Name:";
			// 
			// radMultipleServers
			// 
			this.radMultipleServers.Location = new System.Drawing.Point(328, 16);
			this.radMultipleServers.Name = "radMultipleServers";
			this.radMultipleServers.Size = new System.Drawing.Size(128, 16);
			this.radMultipleServers.TabIndex = 1;
			this.radMultipleServers.Text = "Multiple Servers";
			// 
			// radSingleServer
			// 
			this.radSingleServer.Location = new System.Drawing.Point(8, 16);
			this.radSingleServer.Name = "radSingleServer";
			this.radSingleServer.Size = new System.Drawing.Size(112, 16);
			this.radSingleServer.TabIndex = 0;
			this.radSingleServer.Text = "Single Server";
			// 
			// gbScripts
			// 
			this.gbScripts.Controls.Add(this.btnAddToList);
			this.gbScripts.Controls.Add(this.label5);
			this.gbScripts.Controls.Add(this.lbScripts);
			this.gbScripts.Controls.Add(this.btnBrowse);
			this.gbScripts.Controls.Add(this.txtFilePath);
			this.gbScripts.Location = new System.Drawing.Point(8, 200);
			this.gbScripts.Name = "gbScripts";
			this.gbScripts.Size = new System.Drawing.Size(704, 152);
			this.gbScripts.TabIndex = 10;
			this.gbScripts.TabStop = false;
			this.gbScripts.Text = "Scripts";
			// 
			// btnAddToList
			// 
			this.btnAddToList.Location = new System.Drawing.Point(584, 72);
			this.btnAddToList.Name = "btnAddToList";
			this.btnAddToList.TabIndex = 10;
			this.btnAddToList.Text = "Add To List";
			this.btnAddToList.Click += new System.EventHandler(this.btnAddToList_Click);
			// 
			// label5
			// 
			this.label5.Location = new System.Drawing.Point(272, 16);
			this.label5.Name = "label5";
			this.label5.Size = new System.Drawing.Size(96, 16);
			this.label5.TabIndex = 9;
			this.label5.Text = "Script File:";
			// 
			// lbScripts
			// 
			this.lbScripts.Location = new System.Drawing.Point(8, 24);
			this.lbScripts.Name = "lbScripts";
			this.lbScripts.Size = new System.Drawing.Size(216, 109);
			this.lbScripts.TabIndex = 8;
			// 
			// btnBrowse
			// 
			this.btnBrowse.Location = new System.Drawing.Point(664, 32);
			this.btnBrowse.Name = "btnBrowse";
			this.btnBrowse.Size = new System.Drawing.Size(24, 24);
			this.btnBrowse.TabIndex = 7;
			this.btnBrowse.Text = "...";
			this.btnBrowse.Click += new System.EventHandler(this.btnBrowse_Click);
			// 
			// txtFilePath
			// 
			this.txtFilePath.Location = new System.Drawing.Point(272, 40);
			this.txtFilePath.Name = "txtFilePath";
			this.txtFilePath.Size = new System.Drawing.Size(384, 20);
			this.txtFilePath.TabIndex = 6;
			this.txtFilePath.Text = "";
			// 
			// gbDatabaseParameters
			// 
			this.gbDatabaseParameters.Controls.Add(this.txtPassword);
			this.gbDatabaseParameters.Controls.Add(this.label4);
			this.gbDatabaseParameters.Controls.Add(this.txtUserAccount);
			this.gbDatabaseParameters.Controls.Add(this.label3);
			this.gbDatabaseParameters.Controls.Add(this.txtDatabaseName);
			this.gbDatabaseParameters.Controls.Add(this.label1);
			this.gbDatabaseParameters.Location = new System.Drawing.Point(8, 104);
			this.gbDatabaseParameters.Name = "gbDatabaseParameters";
			this.gbDatabaseParameters.Size = new System.Drawing.Size(712, 88);
			this.gbDatabaseParameters.TabIndex = 9;
			this.gbDatabaseParameters.TabStop = false;
			this.gbDatabaseParameters.Text = "Database Parameters";
			// 
			// txtPassword
			// 
			this.txtPassword.Location = new System.Drawing.Point(376, 56);
			this.txtPassword.Name = "txtPassword";
			this.txtPassword.PasswordChar = '*';
			this.txtPassword.TabIndex = 15;
			this.txtPassword.Text = "";
			// 
			// label4
			// 
			this.label4.Location = new System.Drawing.Point(256, 56);
			this.label4.Name = "label4";
			this.label4.Size = new System.Drawing.Size(88, 16);
			this.label4.TabIndex = 14;
			this.label4.Text = "Password:";
			// 
			// txtUserAccount
			// 
			this.txtUserAccount.Location = new System.Drawing.Point(376, 24);
			this.txtUserAccount.Name = "txtUserAccount";
			this.txtUserAccount.TabIndex = 13;
			this.txtUserAccount.Text = "";
			// 
			// label3
			// 
			this.label3.Location = new System.Drawing.Point(256, 24);
			this.label3.Name = "label3";
			this.label3.Size = new System.Drawing.Size(88, 16);
			this.label3.TabIndex = 12;
			this.label3.Text = "User Account:";
			// 
			// txtDatabaseName
			// 
			this.txtDatabaseName.Location = new System.Drawing.Point(136, 24);
			this.txtDatabaseName.Name = "txtDatabaseName";
			this.txtDatabaseName.TabIndex = 9;
			this.txtDatabaseName.Text = "";
			// 
			// label1
			// 
			this.label1.Location = new System.Drawing.Point(16, 24);
			this.label1.Name = "label1";
			this.label1.Size = new System.Drawing.Size(88, 16);
			this.label1.TabIndex = 8;
			this.label1.Text = "Database:";
			// 
			// btnGo
			// 
			this.btnGo.Location = new System.Drawing.Point(560, 360);
			this.btnGo.Name = "btnGo";
			this.btnGo.Size = new System.Drawing.Size(120, 23);
			this.btnGo.TabIndex = 8;
			this.btnGo.Text = "Run Selected Scripts";
			this.btnGo.Click += new System.EventHandler(this.btnGo_Click);
			// 
			// timer1
			// 
			this.timer1.Interval = 60000;
			this.timer1.Tick += new System.EventHandler(this.timer1_Tick);
			// 
			// tbStatus
			// 
			this.tbStatus.Dock = System.Windows.Forms.DockStyle.Bottom;
			this.tbStatus.Location = new System.Drawing.Point(0, 406);
			this.tbStatus.Multiline = true;
			this.tbStatus.Name = "tbStatus";
			this.tbStatus.Size = new System.Drawing.Size(736, 64);
			this.tbStatus.TabIndex = 1;
			this.tbStatus.Text = "";
			// 
			// frmMain
			// 
			this.AutoScaleBaseSize = new System.Drawing.Size(5, 13);
			this.ClientSize = new System.Drawing.Size(736, 470);
			this.Controls.Add(this.tbStatus);
			this.Controls.Add(this.panel1);
			this.Name = "frmMain";
			this.Text = "Simple Quick Script Runner";
			this.Closing += new System.ComponentModel.CancelEventHandler(this.frmMain_Closing);
			this.panel1.ResumeLayout(false);
			this.groupBox1.ResumeLayout(false);
			this.gbScripts.ResumeLayout(false);
			this.gbDatabaseParameters.ResumeLayout(false);
			this.ResumeLayout(false);

		}
		#endregion

		/// <summary>
		/// The main entry point for the application.
		/// </summary>
		[STAThread]
		static void Main() 
		{
			frmMain frm = new frmMain();
			//TODO: add a way to feed multiple server names
			//TODO: add a way to add multiple scripts as a part of a job...
			Application.Run(frm);
		}

		private void btnAddToList_Click(object sender, System.EventArgs e)
		{
			//add it to the list of scripts
			lbScripts.Items.Add(txtFilePath.Text,true);

			txtFilePath.Text = "";
		}	

		private void btnBrowse_Click(object sender, System.EventArgs e)
		{
			OpenFileDialog1.Filter = "SQL Scripts (*.sql)|*.sql";
			//show the file open
			OpenFileDialog1.ShowDialog();
				
			//if a file was selected
			if (OpenFileDialog1.FileName != "")
			{
				//display it in the text box
				txtFilePath.Text = OpenFileDialog1.FileName;
			}
		}

		private void btnBrowseForServersFile_Click(object sender, System.EventArgs e)
		{
			OpenFileDialog1.Filter = "Text Files (*.txt)|*.txt|All Files (*.*)|*.*";
			//show the file open
			OpenFileDialog1.ShowDialog();
				
			//if a file was selected
			if (OpenFileDialog1.FileName != "")
			{
				//display it in the text box
				txtServersFile.Text = OpenFileDialog1.FileName;
			}
		}

		private void btnGo_Click(object sender, System.EventArgs e)
		{
			if (isValidated() == true)
			{	
				if (radSingleServer.Checked == true)
				{
					timer1.Interval = 1000;
				}

				timer1.Enabled = true;
			}
		}

		private void frmMain_Closing(object sender, System.ComponentModel.CancelEventArgs e)
		{
			SaveQueueToFile();
		}

		private void timer1_Tick(object sender, System.EventArgs e)
		{
			//pull in any new files
			BuildQueue();
			//if any exists
			if (mServerQueue.Count > 0)
			{
				//kick off the job
				RunJob((String)mServerQueue.Dequeue());
			}
		}

		private bool isValidated()
		{
			//at least on script spec'd
			if (lbScripts.Items.Count <=0)
			{
				MessageBox.Show("At least one script must be added.");
				txtFilePath.Focus();
				return false;
			}

			return true;
		}

		private ScriptRunner buildScriptRunner()
		{
			//TODO: model a way to cache the script runner, if the list of scripts does not change... (i.e. changes in the files...)
			ScriptRunner myRunner = new ScriptRunner();

			//build the script runner off the given file
			foreach (String scriptFile in lbScripts.Items)
			{
				myRunner.AppendScript(new FileInfo(scriptFile));
			}
			
			return myRunner;
		}

		private void BuildQueue()
		{
			String serverName = "";

			if (radMultipleServers.Checked)
			{
				//pick off the first computer in the list
				StreamReader sr = new StreamReader(txtServersFile.Text);

				// Read and display lines from the file until the end of 
				// the file is reached.
				while ((serverName = sr.ReadLine()) != null) 
				{
					if (serverName.Trim().Length >0)
					{
						mServerQueue.Enqueue(serverName);
					}					
				}

				sr.Close();

				//clear the file
				StreamWriter sw = new StreamWriter(txtServersFile.Text);
				sw.Write("");
				sw.Close();
			}
			else
			{
				serverName = txtServer.Text;
				mServerQueue.Enqueue(serverName);
			}			
		}

		private void  SaveQueueToFile()
		{
			if (mServerQueue.Count >0)
			{
                StreamWriter sw = new StreamWriter(txtServersFile.Text,true);

				System.Collections.IEnumerator myEnumerator = mServerQueue.GetEnumerator();
				while ( myEnumerator.MoveNext() )
				{
					sw.WriteLine(myEnumerator.Current);
				}

				sw.Close();
			}
		}

		private void RunJob(String ServerName)
		{
			ScriptRunner myRunner = buildScriptRunner();		

			//construct the conn string
			String prodString = 
				"Persist Security Info=False;" +
				"User ID=" + txtUserAccount.Text + ";" +
				"Initial Catalog=" + txtDatabaseName.Text + ";" +
				"Data Source=" + ServerName + ";" + 
				"Packet Size=4096;Password=" + txtPassword.Text;

			try
			{
				//run
				String results = myRunner.RunAgainst(prodString);


				tbStatus.Text = ServerName + " Processed!" + "\n" + results + "\n";
				ReportProgress(ServerName + " Processed!" + "\n" + results + "\n");
				System.Diagnostics.Debug.Write(tbStatus.Text);
			}
			catch (Exception ex)
			{
				tbStatus.Text = ServerName + " Failed!" + "\n" + ex.ToString() + "\n";
				ReportProgress(ServerName + " Failed!" + "\n" + ex.ToString() + "\n");

				//add the server back to the queue
				mServerQueue.Enqueue(ServerName);
			}

			// Create the delegate.
			//AsyncDelegate dlgt = new AsyncDelegate(myRunner.RunAgainst);
			//AsyncCallback acDlgt = new AsyncCallback(this.CallbackMethod);

			// Initiate the asychronous call.  Include an AsyncCallback
			// delegate representing the callback method, and the data
			// needed to call EndInvoke.
			//IAsyncResult ar = dlgt.BeginInvoke(prodString,acdlgt,dlgt);
		}

		private void ReportProgress(String text)
		{
			String logFileName;

			if (txtServersFile.Text != "")
			{
				logFileName = new System.IO.FileInfo(txtServersFile.Text).DirectoryName + @"\PFGLog.txt";
			}
			else
			{
				logFileName = new System.IO.FileInfo(Application.ExecutablePath).DirectoryName + @"\PFGLog.txt";
			}			

			using (StreamWriter sw = new StreamWriter(logFileName,true))
			{
				sw.WriteLine(text);
				sw.Close();
			}
		}

		// Callback method must have the same signature as the
		// AsyncCallback delegate.
		private void CallbackMethod(IAsyncResult ar) 
		{
			// Retrieve the delegate.
			AsyncDelegate dlgt = (AsyncDelegate) ar.AsyncState;

			// Call EndInvoke to retrieve the results.
			string ret = dlgt.EndInvoke(ar);

			//update UI

			//mark record as completed
		}
	}
}
